Run cargo off the main thread.
authorAlex Crichton <alex@alexcrichton.com>
Sat, 16 Aug 2014 22:00:38 +0000 (15:00 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Sat, 16 Aug 2014 23:16:32 +0000 (16:16 -0700)
On windows the main thread suffers the same fate as rustdoc (as linked in the
comments), and hence needs to run off the main thread for now.

src/cargo/lib.rs
src/cargo/sources/git/utils.rs
tests/test_cargo_compile_git_deps.rs

index 0240a36f3e7f9c3efe052831ed823ebcbf054b9a..f701553d302c78beb46728bc37aa76fb7e7e730a 100644 (file)
@@ -84,7 +84,10 @@ pub fn execute_main<'a,
                     V: Encodable<json::Encoder<'a>, io::IoError>>(
                         exec: fn(T, U, &mut MultiShell) -> CliResult<Option<V>>,
                         options_first: bool) {
-    process::<V>(|rest, shell| call_main(exec, shell, rest, options_first));
+    // see comments below
+    off_the_main_thread(proc() {
+        process::<V>(|rest, shell| call_main(exec, shell, rest, options_first));
+    });
 }
 
 pub fn call_main<'a,
@@ -106,8 +109,11 @@ pub fn execute_main_without_stdin<'a,
                                   V: Encodable<json::Encoder<'a>, io::IoError>>(
                                       exec: fn(T, &mut MultiShell) -> CliResult<Option<V>>,
                                       options_first: bool) {
-    process::<V>(|rest, shell| call_main_without_stdin(exec, shell, rest,
-                                                       options_first));
+    // see comments below
+    off_the_main_thread(proc() {
+        process::<V>(|rest, shell| call_main_without_stdin(exec, shell, rest,
+                                                           options_first));
+    });
 }
 
 pub fn call_main_without_stdin<'a,
@@ -240,3 +246,16 @@ fn json_from_stdin<T: RepresentsJSON>() -> CliResult<T> {
         CliError::new("Could not process standard in as input", 1)
     })
 }
+
+// Seems curious to run cargo off the main thread, right? Well do I have a story
+// for you. Turns out rustdoc does a similar thing, and already has a good
+// explanation [1] though, so I'll just point you over there.
+//
+// [1]: https://github.com/rust-lang/rust/blob/85fd37f/src/librustdoc/lib.rs#L92-L122
+fn off_the_main_thread(p: proc():Send) {
+    let (tx, rx) = channel();
+    spawn(proc() { p(); tx.send(()); });
+    if rx.recv_opt().is_err() {
+        std::os::set_exit_status(std::rt::DEFAULT_ERROR_CODE);
+    }
+}
index 3894879e6df5f47560fabc8bd50f68016bca6de4..59a19b6ee10ce1974c6dece9135a088f10bcc2d8 100644 (file)
@@ -148,10 +148,14 @@ impl GitRemote {
     pub fn checkout(&self, into: &Path) -> CargoResult<GitDatabase> {
         let repo = if into.exists() {
             let r = try!(git2::Repository::open(into));
-            try!(self.fetch_into(&r));
+            try!(self.fetch_into(&r).chain_error(|| {
+                internal(format!("failed to fetch into {}", into.display()))
+            }));
             r
         } else {
-            try!(self.clone_into(into))
+            try!(self.clone_into(into).chain_error(|| {
+                internal(format!("failed to clone into: {}", into.display()))
+            }))
         };
 
         Ok(GitDatabase { remote: self.clone(), path: into.clone(), repo: repo })
@@ -179,6 +183,7 @@ impl GitRemote {
 
     fn clone_into(&self, dst: &Path) -> CargoResult<git2::Repository> {
         let url = self.url.to_string();
+        try!(mkdir_recursive(dst, UserDir));
         let repo = try!(git2::build::RepoBuilder::new().bare(true)
                                                        .hardlinks(false)
                                                        .clone(url.as_slice(), dst));
@@ -222,7 +227,10 @@ impl<'a> GitCheckout<'a> {
         // If the git checkout already exists, we don't need to clone it again
         let repo = match git2::Repository::open(into) {
             Ok(repo) => repo,
-            Err(..) => try!(GitCheckout::clone_repo(database.get_path(), into)),
+            Err(..) => {
+                try!(mkdir_recursive(&into.dir_path(), UserDir));
+                try!(GitCheckout::clone_repo(database.get_path(), into))
+            }
         };
         Ok(GitCheckout {
             location: into.clone(),
@@ -251,7 +259,11 @@ impl<'a> GitCheckout<'a> {
 
         let url = try!(source.to_url().map_err(human));
         let url = url.to_string();
-        let repo = try!(git2::Repository::clone(url.as_slice(), into));
+        let repo = try!(git2::Repository::clone(url.as_slice(),
+                                                into).chain_error(|| {
+            internal(format!("failed to clone {} into {}", source.display(),
+                             into.display()))
+        }));
         Ok(repo)
     }
 
index 241dc2ba938231ce6b8d04f16886a815d869a5c1..18bd5f634d79e96167b5218ecee46a7109540cd0 100644 (file)
@@ -907,7 +907,7 @@ test!(dep_with_changed_submodule {
                 .with_stdout(format!("{} git repository `[..]`\n\
                                       {} dep1 v0.5.0 ([..])\n\
                                       {} foo v0.5.0 ([..])\n\
-                                      {} `target/foo`\n\
+                                      {} `target[..]foo`\n\
                                       project2\
                                       ",
                                       UPDATING,
@@ -919,7 +919,7 @@ test!(dep_with_changed_submodule {
 
     let mut file = File::create(&git_project.root().join(".gitmodules"));
     file.write_str(format!("[submodule \"src\"]\n\tpath = src\n\turl={}",
-                           git_project3.root().display()).as_slice());
+                           git_project3.url()).as_slice());
 
     git_project.process("git").args(["submodule", "sync"]).exec_with_output().assert();
     git_project.process("git").args(["fetch"]).cwd(git_project.root().join("src"))
@@ -942,7 +942,7 @@ test!(dep_with_changed_submodule {
                 .with_stdout(format!("{} git repository `[..]`\n\
                                       {} dep1 v0.5.0 ([..])\n\
                                       {} foo v0.5.0 ([..])\n\
-                                      {} `target/foo`\n\
+                                      {} `target[..]foo`\n\
                                       project3\
                                       ",
                                       UPDATING,